package com.wxw.BaseLibrary.http;

import android.content.Context;
import android.database.Cursor;
import com.wxw.BaseLibrary.db.DBTool;
import com.wxw.BaseLibrary.http.soap.SoapListener;
import com.wxw.BaseLibrary.infa.IDbObject;
import com.wxw.BaseLibrary.infa.IGeneralEventCallback;
import com.wxw.BaseLibrary.tool.CopyOnWriteMap;
import com.wxw.BaseLibrary.tool.ToolsDate;

import java.util.ArrayList;
import java.util.concurrent.CopyOnWriteArrayList;

/**
 *
 * @author david
 * @date 2014/4/10
 */
public class RequestManager implements RequestCompletedListener {
    public static final String TAG = "ReqManager";
    private Context _context;
    private DBTool dbTool = null;
    public static int ForeverRequestCommitStep = 60;
//    private int RequestCommitStep = 5;
    public static int HTTP_Response_Timeout = 60000;
    public static String WEBSERVICE_SERVER_ADDRESS = "";
    public static String DefaultRequestService = "";
    public static boolean networkIsOK = true;
    private int iTaskCount = 0;
    private int iTaskLimit = 3;
    private static RequestManager requestManager;
    private IRequestTaskFactory factory = null;
    private CopyOnWriteArrayList<IRequestTask> tasks = null;
    private boolean running = false;
    private boolean pause = false;
    private CopyOnWriteArrayList<IGeneralEventCallback> eventCallbacks = null;
    private CopyOnWriteMap<String, SoapListener> soapListeners = null;
    private CopyOnWriteArrayList<RequestTaskCompletedListener> requestTaskCompletedListeners = null;
    private Object lockObj = new Object();
    private Thread mainThread;

    public void addGeneralEventListener(IGeneralEventCallback generalEventCallback){
        if (!eventCallbacks.contains(generalEventCallback)) {
            eventCallbacks.add(generalEventCallback);
        }
    }

    public void removeGeneralEventListener(IGeneralEventCallback generalEventCallback){
        eventCallbacks.remove(generalEventCallback);

    }

    public void addRequestTaskCompletedListener(RequestTaskCompletedListener listener) {
        if (!requestTaskCompletedListeners.contains(listener)) {
            requestTaskCompletedListeners.add(listener);
        }
    }

    public void removeRequestTaskCompletedListener(RequestTaskCompletedListener listener) {
        requestTaskCompletedListeners.remove(listener);
    }

    public void addSoapListener(String key, SoapListener listener) {
        soapListeners.put(key, listener);
    }

    public void removeSoapListener(String key) {
        soapListeners.remove(key);
    }


    public Context getContext() {
        return _context;
    }

    public void setContext(Context _context) {
        this._context = _context;
    }

    public IRequestTaskFactory getFactory() {
        return factory;
    }

    public void setFactory(IRequestTaskFactory factory) {
        this.factory = factory;
    }

    public int getTaskCount() {
        return iTaskCount;
    }

    public int getTaskLimit() {
        return iTaskLimit;
    }

    public void setTaskLimit(int iTaskLimit) {
        this.iTaskLimit = iTaskLimit;
    }

    public void setRunning(boolean running) {
        this.running = running;
    }

    public void start() {
        if (mainThread != null) {
            running = false;
            try {
                mainThread.interrupt();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        mainThread = new Thread(new Runnable() {
            @Override
            public void run() {
                RequestManager.this.run();
            }
        });
        mainThread.start();
    }

    public void stop() {
        running = false;
    }

    public void pause() {
        pause = true;
    }

    public void resumed() {
        pause = false;
    }

    private RequestManager(){
        eventCallbacks = new CopyOnWriteArrayList<IGeneralEventCallback>();
        requestTaskCompletedListeners = new CopyOnWriteArrayList<RequestTaskCompletedListener>();
        soapListeners = new CopyOnWriteMap<String, SoapListener>();
        tasks = new CopyOnWriteArrayList<IRequestTask>();
        dbTool = DBTool.getInstance();
        dbTool.execSQL("Delete From " + RequestMessage.TABLE_NAME + " Where Status>0 And LastUpdate<date('now', '-3 day')");
    }

    public static synchronized RequestManager getRequestManager(){
        if (requestManager == null) {
            requestManager = new RequestManager();
        }
        return requestManager;
    }

    public static synchronized RequestManager getRequestManager(IRequestTaskFactory factory) {
        RequestManager manager = getRequestManager();
        manager.setFactory(factory);
        return manager;
    }

    private void run(){
        running = true;
        while (running){
            try {
                if (pause) {
                    Thread.sleep(5000);
                    continue;
                }
                if (tasks.size() == iTaskLimit) {
                    Thread.sleep(1000);
                    continue;
                }
                RequestMessage message = getRequestMessage();
                if (message != null) {
                    if (message.Forever && message.CountDown > 0) {
                        message.LastUpdate = ToolsDate.getDateLine();
                        message.CountDown--;
                        message.update(DBTool.getInstance());
                    } else {
                        message.Status = RequestMessageStatus.Submit;
                        message.LastUpdate = ToolsDate.getDateLine();
                        message.update(DBTool.getInstance());
                        IRequestTask task = null;
                        if (factory == null) {
                            factory = new DefaultRequestTaskFactory();
                        }
                        task = factory.createRequestTask(RequestManager.this, message);
                        task.setSoapListener(soapListeners.get(message.MessageKey));
                        task.setRequestCompletedListener(this);
                        tasks.add(task);
                        iTaskCount = tasks.size();
                        task.startTask();
                        triggerEvent();
                    }
                }
                Thread.sleep(1000);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    private RequestMessage getRequestMessage() {
        Cursor cursor = dbTool.query("Select * From " + RequestMessage.TABLE_NAME + " Where Status<1 Order By LastUpdate limit 0,1");
        IDbObject message = new RequestMessage();
        message = message.full(cursor);
        return message==null?null:(RequestMessage)message;
    }

    private void triggerEvent(){
        if (eventCallbacks==null || eventCallbacks.size()<=0) {
            return;
        }
        ArrayList<IGeneralEventCallback> temp = new ArrayList<IGeneralEventCallback>();
        for (IGeneralEventCallback generalEventCallback : eventCallbacks) {
            try {
                generalEventCallback.finished(this, String.valueOf(iTaskCount));
            } catch (Exception e){
                e.printStackTrace();
                temp.add(generalEventCallback);
            }
        }
        if (temp.size()>0){
            for (IGeneralEventCallback generalEventCallback : temp) {
                eventCallbacks.remove(generalEventCallback);
            }
        }
    }

    @Override
    public void onCompleted(Object sender, RequestMessage message) {
        //synchronized (lockObj) {
            if (tasks.contains(sender)) {
                tasks.remove(sender);
                iTaskCount = tasks.size();
            }
            RequestTaskCompletedListener listener1 = null;
            for (RequestTaskCompletedListener listener : requestTaskCompletedListeners) {
                if (listener.getKey().equals(message.MessageKey)) {
                    listener.onCompleted(sender, message);
                    listener1 = listener;
                }
            }
            if (listener1 != null) {
                requestTaskCompletedListeners.remove(listener1);
            }
        //}
        triggerEvent();
    }
}
